package com.example.demo.controller;

import com.example.demo.common.Result;
import com.example.demo.entity.Borrow;
import com.example.demo.entity.User;
import com.example.demo.entity.dto.*;
import com.example.demo.mapper.*;
import com.example.demo.service.impl.BookService;
import com.example.demo.service.impl.BorrowService;
import com.example.demo.service.impl.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/views")
public class Views {
    @Autowired
    private BookService bookService;
    @Autowired
    private BorrowService borrowService;
    @Autowired
    private BookMapper bookMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private TopBorrowedBookMapper topBorrowedBookMapper;
    @Autowired
    private BorrowMapper borrowMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private UserService userService;

    //分类扇形比例图
    @GetMapping("/categoryBorrowCount")
    public Result getCategoryBorrowCount() {
        //如果缓存中不存在数据，则从数据库中获取数据
        String key = "categoryBorrowCount";
        List<Map<String, Object>> data = (List<Map<String, Object>>) redisTemplate.opsForValue().get(key);
        if (data == null) {
            data = bookService.getCategoryBorrowCount();
            redisTemplate.opsForValue().set(key, data, 1, TimeUnit.HOURS);
        }
        return Result.success(data);
    }


    //1借阅总数今日借出本月借出 今日还入本月还入
    @GetMapping("/borrowCount")
    public Result countBorrow() {
        HashMap<String, Integer> result = new HashMap<>();
        result.put("dayTotal", totalTodayBorrow());
        result.put("monthTotal", totalMonthBorrow());
        return Result.success(result);
    }

    //2本月借阅书籍top5图表
    @GetMapping("/topBorrowedBooks")
    public Result getTopBorrowedBooks() {
        //如果缓存中不存在数据，则从数据库中获取数据;如果缓存存在则判断是否过期，如果过期则从数据库中获取数据；如果缓存存入的时间早于最新订单的时间则从数据库中获取数据
        String key = "topBorrowedBooks";
        List<TopBorrowedBook> list = (List<TopBorrowedBook>) redisTemplate.opsForValue().get(key);
        if (list == null) {
            list = topBorrowedBookMapper.getTopBorrowedBooks();
            redisTemplate.opsForValue().set(key, list, 1, TimeUnit.HOURS);
        } else {
            //如果缓存存在则判断是否过期，如果过期则从数据库中获取数据；如果缓存存入的时间早于最新订单的时间则从数据库中获取数据
            Object latestOrderTime = redisTemplate.opsForValue().get("latest_order_time");
            if (latestOrderTime instanceof LocalDateTime && ((LocalDateTime) latestOrderTime).isBefore(LocalDateTime.now())) {
                list = topBorrowedBookMapper.getTopBorrowedBooks();
                redisTemplate.opsForValue().set(key, list, 1, TimeUnit.HOURS);
            }

        }
        return Result.success(list);
    }

    //3十条最新数据
    @GetMapping("/borrows10")
    public Result listRecentBorrows() {
        List<Borrow> orders = borrowMapper.selectLatestBorrow(10);
        // 返回成功响应，并将查询结果作为数据返回
        return Result.success(orders);
    }

    //4年级借阅分布扇形图
    @GetMapping("/gradeBorrowedCountPie")
    public Result getGradeBorrowedCountPie() {
        // 获取当前年份
        int currentYear = LocalDate.now().getYear();
        // 定义一个空的结果集
        Map<String, Integer> result = new HashMap<>();
        // 遍历当前年份的四个年级
        for (int i = 1; i <= 4; i++) {
            int grade = currentYear - i + 1;
            // 调用 Mapper 方法获取该年级的借阅统计数据
            int count = borrowMapper.selectGradeBorrowedCountByGrade(grade);
            result.put(String.valueOf(grade), count);
        }
        // 将结果集按照指定格式进行转换
        Map<String, Integer> formattedData = new HashMap<>();
        for (int i = 1; i <= 4; i++) {
            int grade = currentYear - i + 1;
            formattedData.put(String.valueOf(grade), result.getOrDefault(String.valueOf(grade), 0));
        }
        return Result.success(formattedData);
    }

    //6年度借阅月份图折线图
    @GetMapping("/borrowCountByMonth")
    public Result getBorrowLineChart() {
        List<Object[]> scatterData = new ArrayList<>();
        int currentYear = LocalDate.now().getYear();
        int previousYear = currentYear - 1;
        List<BorrowCountByMonth> borrowCounts = borrowMapper.getBorrowCountByMonth();
        for (BorrowCountByMonth borrowCount : borrowCounts) {
            String[] parts = borrowCount.getMonth().split("-");
            int year = Integer.parseInt(parts[0]);
            int month = Integer.parseInt(parts[1]);
            // 当前年份和上一年份的数据分别存储到不同的数组中
            if (year == currentYear) {
                scatterData.add(new Object[]{"当前年份", month, borrowCount.getCount()});
            } else if (year == previousYear) {
                scatterData.add(new Object[]{"上一年份", month, borrowCount.getCount()});
            }
        }
        return Result.success(scatterData);
    }

    //7近一个星期每天的借阅数量
    @GetMapping("/borrowCountByWeek")
    public Result countBorrowByWeek() {
        String key = "borrowCountByWeek";
        Map<String, Integer> result = (Map<String, Integer>) redisTemplate.opsForValue().get(key);
        if (result == null) {
            List<Map<String, Object>> list = borrowMapper.countBorrowByWeek();
            result = new LinkedHashMap<>();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            SimpleDateFormat weekSdf = new SimpleDateFormat("E"); // 获取星期几，如周一、周二等
            // 初始化结果 Map，将星期几作为键，值为 0，按照从周一到周日的顺序
            String[] weekdays = new String[]{"周一", "周二", "周三", "周四", "周五", "周六", "周日"};
            for (int i = 0; i < 7; i++) {
                result.put(weekdays[i], 0);
            }
            // 遍历查询结果，计算出对应的星期几，将星期几作为键，借阅数量作为值存入结果 Map 中
            for (int i = list.size() - 1; i >= 0; i--) {
                Map<String, Object> map = list.get(i);
                String dateStr = map.get("borrowDate").toString();
                int count = ((Long) map.get("count")).intValue();
                try {
                    Date date = sdf.parse(dateStr);
                    String weekStr = weekSdf.format(date);
                    // 将星期几改为从周一开始计算
                    int index = Arrays.asList(weekdays).indexOf(weekStr);
                    if (index >= 0) {
                        weekStr = weekdays[(index + 6) % 7];
                    }
                    result.put(weekStr, count);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
            redisTemplate.opsForValue().set(key, result, 1, TimeUnit.MINUTES);
        }
        return Result.success(result);
    }

    //8借阅量最多的十个专业和借阅数量
    @GetMapping("/topBorrowedMajors")
    public Result getTopBorrowedMajors() {
        // 如果缓存中不存在数据，则从数据库中获取数据
        String key = "topBorrowedMajors";
        List<Map<String, Integer>> data = (List<Map<String, Integer>>) redisTemplate.opsForValue().get(key);
        if (data == null) {
            data = borrowMapper.getBorrowedUsersByMajorWithParity();
            redisTemplate.opsForValue().set(key, data, 1, TimeUnit.HOURS);
        }
        // 构建返回结果
        List<Map<String, Object>> result = new ArrayList<>();
        for (Map<String, Integer> item : data) {
            Map<String, Object> map = new HashMap<>();
            map.put("major", item.get("user_major"));
            map.put("value", item.get("count"));
            result.add(map);
        }
        return Result.success(result);
    }

    @GetMapping("/redis/{id}")
    public User getUserById(@PathVariable("id") Long id) {
        // 从 Redis 缓存中获取用户信息
        String key = "user:" + id;
        User user = (User) redisTemplate.opsForValue().get(key);
        if (user == null) {
            // 如果缓存中不存在用户信息，则从数据库中获取用户信息
            user = userService.getById(id);
            // 将用户信息存入 Redis 缓存，并设置过期时间为 1 小时
            redisTemplate.opsForValue().set(key, user, 1, TimeUnit.HOURS);
        }
        return user;
    }

    //今日借出
    public Integer totalTodayBorrow() {
        LocalDateTime startTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
        return borrowMapper.countBetween(startTime, endTime);
    }

    //本月借出
    public Integer totalMonthBorrow() {
        LocalDateTime startTime = LocalDateTime.of(LocalDate.now().minusMonths(1), LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
        return borrowMapper.countBetween(startTime, endTime);
    }

    //清空缓存
    @GetMapping("/clearCache")
    public Result clearCache() {
        redisTemplate.delete(redisTemplate.keys("*"));
        return Result.success();
    }

    //获取剩余和总数
    @GetMapping("/remainAndTotal")
    public Result getRemainAndTotal() {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("remain", getRemain());
        map.put("total", getTotal());
        return Result.success(map);
    }

    //查看自己借阅图书的数量根据id
    @GetMapping("/getBorrowCountById")
    public Result getBorrowCountById(@RequestParam("id") Integer id) {
        return Result.success(borrowMapper.getBorrowCountById(id));
    }

    /**
     * 个人分类借阅
     *
     * @return
     */

    @GetMapping("/getCategoryBorrowUser")
    public Result getCategoryBorrowUser(Integer id) {
        return Result.success(borrowMapper.getCategoryBorrowUser(id));
    }

    public int getRemain() {
        return bookMapper.getRemain();
    }

    public int getTotal() {
        return bookMapper.getTotal();
    }
    /**
     * 个人借阅数折线图
     */
    @GetMapping("/getBorrowData")
    public Result getBorrowData(String userId, @DateTimeFormat(pattern="yyyy-MM-dd")
    LocalDate startDate,@DateTimeFormat(pattern="yyyy-MM-dd") LocalDate endDate) {
        List<Map<String, Object>> borrowData = borrowService.getBorrowData(userId, startDate, endDate);
        return Result.success(borrowData);
    }
}

